package engine.services.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.security.util.InMemoryResource;
import org.springframework.ui.velocity.VelocityEngineUtils;

import engine.content.ContentTypes;
import engine.content.FileContent;
import engine.content.HtmlContent;
import engine.content.IContent;
import engine.content.InMemoryContent;
import engine.dataobjects.Image;
import engine.dataobjects.MailItem;
import engine.dataobjects.MailItemInstance;
import engine.mail.IMailMessage;
import engine.services.IContentService;
import engine.services.IImageService;
import engine.services.IMailSender;
import engine.services.IMailService;

public class MailService  implements IMailService {
	private static Log log = LogFactory.getLog(MailService.class);

	private boolean isDebugMode = false;
	
	private MailService() {
		
	}
	
	@Autowired
	IImageService imageService;
	
	public void setImageService(IImageService imageService) {
		this.imageService = imageService;
	}

	@Override
	public void setDebugMode() {
		isDebugMode = true;
	}
	
	/* (non-Javadoc)
	 * @see engine.beans.IMailService#mail(dataobjects.Message)
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void mail(MailItemInstance instance) {
		try {
			MailItem item = instance.getItem();
			IMailMessage mm = mailSender.createMessage();
			if (isDebugMode) {
				instance.getTo().clear();
				instance.getTo().add(debugToAdress);
			}
			if (instance.getTo() == null || instance.getTo().size() == 0) {
				log.warn("This message has no recipients. Message: " + item.getName());
				return;
			}
			mm.setTo(instance.getTo());
			mm.setSubject(item.getName());

			IContent messageContent = getContent(item);
			log.debug("Sending content of type: "+messageContent.getType() +" and content type " + messageContent.getContentType());
			if (messageContent.getType() == ContentTypes.FILE ||
					messageContent.getType() == ContentTypes.MEMORY) {
				handleFile(messageContent, mm, item, mailSender);
			} else {
				mm.setHtmlBody(messageContent.getContentAsString());
			}			

			if (messageContent.getContentBase() != null) {
                mm.addHeader("Content-Base", messageContent.getContentBase());
			}
			mm.setSender(fromAdress);
			mm.setReplyTo(replyToAddress);
			
			mailSender.send(mm);
		} catch (Exception e) {
			log.error("Problem with item: "+ instance.getItem().getName());
			log.error("Problem sending mail." , e);
			throw new RuntimeException(e);
		}
	}
	

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private IContent getContent(MailItem item) throws Exception {
		IContent content = null;
		if (item.getUrl() == null) {
			content = new HtmlContent();
			content.setContent("");
			return content;
		}
		try {
			// getting the content for our message
			content = contentService.getResponse(item);				
		} catch (Exception e) {
			log.error("No content found for: " + item.getUrl(), e);
			throw e;
		}
						
		return content;
	}
	
	@SuppressWarnings("rawtypes")
	void handleFile(IContent messageContent, IMailMessage mm, MailItem item, IMailSender sender) throws Exception {
       
		Resource res;
		if (messageContent.getType() == ContentTypes.FILE) {
			FileContent fc = (FileContent)messageContent;					
        	res = new FileSystemResource(fc.getContent());	            			            		
		} else {
			InMemoryContent mc = (InMemoryContent)messageContent;
        	res = new InMemoryResource(mc.getContent());	            			            			            		
		}

		Map<String, String> tmpltData = new HashMap<String, String>();
		tmpltData.put("replyTo", replyToAddress);
		tmpltData.put("title", item.getName());	
		String description = messageContent.getDescription();
		if (description == null)  description = "";
		tmpltData.put("description", description);
        String tmplt = null;
        String fileId = UUID.randomUUID().toString();
		String fileName = fileId + "." + messageContent.getFileSuffix();
        // can only add this after the text. otherwise image won't show.
        if (
        		messageContent.getFileSuffix().equals("gif") || 
        		messageContent.getFileSuffix().equals("jpeg") || 
        		messageContent.getFileSuffix().equals("jpg") || 
        		messageContent.getFileSuffix().equals("png")) 
		{
        	// checking the size of our image
        	Image img = imageService.getImage(res.getInputStream());
        	int width = img.getWidth();
        	int maxWidth = Math.max(this.maximumWidthImage, item.getMaximumWidthImage());
        	if (maxWidth > 0) {
            	if (width > maxWidth) {
            		float cropPercentage = Float.valueOf(maxWidth)/width;
            		log.debug("cropping image by " + cropPercentage);
            		String dimensionsStr = " width=\""+maxWidth+"\"";
            		int height = img.getHeight();
            		float croppedHeight = cropPercentage * height;
            		dimensionsStr += " height=\""+ (int)croppedHeight+"\"";
            		tmpltData.put("dimensions", dimensionsStr);
            	}
            } else {
            	tmpltData.put("dimensions", "");            	
            }
        	tmpltData.put("cid", fileId);
			tmplt = "emailText_Inline.tmplt";
		} else {
			tmplt = "emailText_File.tmplt";
		}
		sender.addAttachment(messageContent, res, mm, fileName, fileId);
		String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "velocity/" + tmplt, tmpltData);
		mm.setHtmlBody(text);
		mm.addAttachment(messageContent, res, mm, fileName, fileId);
	}
	
	public boolean isDebugMode() {
		return isDebugMode;
	}


	public void setDebugMode(boolean isDebugMode) {
		this.isDebugMode = isDebugMode;
	}

	/****
	 * Injection Parameters
	 */
	private String replyToAddress = null;
	private String fromAdress = null;
	private String debugToAdress = null;
	private int maximumWidthImage = -1;
	
	public void setMaximumWidthImage(int maximumWidthImage) {
		this.maximumWidthImage = maximumWidthImage;
	}


	public void setDebugToAdress(String debugToAdress){
		this.debugToAdress = debugToAdress;
	}

	@Autowired
	private IMailSender mailSender = null;
	
	public void setMailSender(IMailSender mailSender) {
		this.mailSender = mailSender;
	}

	public void setReplyToAddress(String replyToAddress) throws Exception {
		this.replyToAddress = replyToAddress;			
	}

	public void setFromAdress(String fromAdress) throws Exception{
		this.fromAdress = fromAdress;			
	}

	
	@Autowired
	IContentService contentService;
	

	@Autowired
	VelocityEngine velocityEngine;
	
	public void setVelocityEngine(VelocityEngine velocityEngine) {
		this.velocityEngine = velocityEngine;
	}


	public void setContentService(IContentService contentService) {
		this.contentService = contentService;
	}



}
